using System;
using System.Reflection;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Drawing;

using SBPweb.Contracts;
using SBPweb.Contracts.StateManagement;
using SBPweb.Modules.Modularity;
using SBPweb.Modules.Communication;
using SBPweb.Contracts.Implementation;

using SBPweb.Presentation.Windows.Forms.Controls;

// This alias is needed for the module loader to recognize the module's entry point
[assembly: AssemblyDefaultAlias("SBPweb.Modules.StateManagement.StateManagementModule")]

namespace SBPweb.Modules.StateManagement
{
    public class StateManagementModule : ModuleBase
	{

		#region Private members

		private StateManagementService smService;
        private ModuleLoader mModuleLoader;
		private MenuItemControl mModeMenu;
		private MenuItemControl mStateMenu;
		private Dictionary<Mode, List<State>> mStates = null;
		private int mSize = 24;
		private bool pModeMenuVisible = false;
		private bool pStateMenuVisible = false;


        private int mAutoAway = -1;
        private Timer mAwayTimer;
        private Point mLastPosition = Cursor.Position;
        private State mBeforeState;


		#endregion

		#region Constructor logic

		public StateManagementModule(IModuleHost host)
			: base(host)
		{
			Name = "SBPweb.Modules.StateManagement";
            mModuleLoader = host.ModuleLoader;
			AsyncLoad = false;
			smService = new StateManagementService(this, AvailableStates);
            Services.Add(typeof(IStateManagementService), smService);
			pStateMenuVisible = true;
			pModeMenuVisible = true;

            try
            {
                String privatepath = System.Reflection.Assembly.GetExecutingAssembly().Location;
                //AppDomain.CurrentDomain.AppendPrivatePath(System.IO.Path.GetDirectoryName(privatepath));
                System.Configuration.Configuration config = System.Configuration.ConfigurationManager.OpenExeConfiguration(privatepath);

                mAutoAway = Convert.ToInt32(((System.Configuration.ClientSettingsSection)(config.SectionGroups["applicationSettings"].Sections["SBPweb.Modules.StateManagement.Properties.Settings"])).Settings.Get("AutoAway").Value.ValueXml.InnerText);
            }
            catch
            {
            }

            if (mAutoAway > 0)
            {
                if (mAutoAway < 60) mAutoAway = 60;

                mAwayTimer = new Timer();
                mAwayTimer.Interval = mAutoAway * 1000;
                mAwayTimer.Tick += new EventHandler(mAwayTimer_Tick);
                mAwayTimer.Start();
            }
		}

        #endregion

        #region Property accessors

        internal IStateManagementService StateManagementService
        {
            get
            {
				return Services.Get<IStateManagementService>();
            }
        }

		public Dictionary<Mode, List<State>> AvailableStates
		{
			get
			{
				if (mStates == null)
				{
					mStates = GetAvailableStates();
				}
				return mStates;
			}
		}

		public bool ModeMenuVisible
		{
			get
			{
				return pModeMenuVisible;
			}
			set
			{
				pModeMenuVisible = value;
				if (mModeMenu != null)
					mModeMenu.Visible = pModeMenuVisible;
			}
		}
		
		public bool StateMenuVisible
		{
			get
			{
				return pStateMenuVisible;
			}
			set
			{
				pStateMenuVisible = value;
				if (mStateMenu != null)
					mStateMenu.Visible = pStateMenuVisible;
			}
		}

		private ToolStrip StatusBar
		{
			get
			{
				return Host.StatusBar as ToolStrip;
			}
		}
		
		#endregion

        #region Overridden methods

		public override void Dispose()
		{
			this.Services.Remove(typeof(IStateManagementService));
			smService = null;
			base.Dispose();
		}

        public override void Initialize()
        {
			if (HostType != ModuleHostType.WindowsForms)
            {
				Host.LogManager.WriteError(this, "The HostType is not WinForms!", "StateManagement");
                return;
			}

			CreateMenus();
			LoadPersistency();

			smService.ModeChanged += new EventHandler<ModeEventArgs>(smService_ModeChanged);
			smService.StateChanged += new EventHandler<StateEventArgs>(smService_StateChanged);

			ModeMenuVisible = pModeMenuVisible;
			StateMenuVisible = pStateMenuVisible;

			IsInitialized = true;
        }

		#endregion

		#region Menu UI handling

		private delegate void UpdateHandler();

		private void CreateMenus()
		{
			if (StatusBar.InvokeRequired)
			{
				mModeMenu.Owner.BeginInvoke(new UpdateHandler(CreateMenus));
				return;
			}

			mModeMenu = new MenuItemControl();
			Host.StatusBar.Add(mModeMenu);
			mStateMenu = new MenuItemControl();
			Host.StatusBar.Add(mStateMenu);
			mModeMenu.DropDown.Items.Clear();
			UpdateImages();
			(Host.StatusBar as ToolStrip).Resize += new EventHandler(StatusBar_Resize);
			UpdateModeMenu();
		}

		public void UpdateStateMenu()
		{
			if (StatusBar.InvokeRequired)
			{
				mStateMenu.Owner.BeginInvoke(new UpdateHandler(UpdateStateMenu));
				return;
			}

			mStateMenu.Text = StateManagementService.CurrentState.Name;
			mStateMenu.Image = StateManagementService.CurrentState.Icon.ToBitmap().GetThumbnailImage(mSize, mSize, null, IntPtr.Zero);
			mStateMenu.Invalidate();

            #region update Notify Icon
            try
            {
                System.Windows.Forms.NotifyIcon ni = Host.GetType().GetProperty("NotifyIcon").GetValue(Host, null) as System.Windows.Forms.NotifyIcon;
                ni.Text = StateManagementService.CurrentMode.Name + "; " + StateManagementService.CurrentState.Name;
            }
            catch
            {
                //do nothing!!
            }
            #endregion
        }

		public void UpdateModeMenu()
		{
			if (StatusBar.InvokeRequired)
			{
				mModeMenu.Owner.BeginInvoke(new UpdateHandler(UpdateModeMenu));
				return;
			}

			mModeMenu.Text = StateManagementService.CurrentMode.Name;
			mModeMenu.Image = StateManagementService.CurrentMode.Icon.ToBitmap().GetThumbnailImage(mSize, mSize, null, IntPtr.Zero);
			mStateMenu.DropDown.Items.Clear();
			int enabledCount = 0;
			foreach (State s in AvailableStates[StateManagementService.CurrentMode])
			{
				ToolStripItem tsi = mStateMenu.DropDown.Items.Add(s.Name, s.Icon.ToBitmap().GetThumbnailImage(mSize, mSize, null, IntPtr.Zero), new EventHandler(mState_Click));
				tsi.Visible = s.Selectable;
				if (s.Selectable)
					enabledCount = enabledCount + 1;
			}
			if (enabledCount < 2) mStateMenu.DropDown.Items.Clear();
			mModeMenu.Invalidate();
			UpdateStateMenu();
		}

		public void UpdateImages()
		{
			if (StatusBar.InvokeRequired)
			{
				mModeMenu.Owner.BeginInvoke(new UpdateHandler(UpdateImages));
				return;
			}

			mModeMenu.DropDown.Items.Clear();
			int enabledCount = 0;
			foreach (Mode m in AvailableStates.Keys)
			{
				ToolStripItem tsi = mModeMenu.DropDown.Items.Add(m.Name, m.Icon.ToBitmap().GetThumbnailImage(mSize, mSize, null, IntPtr.Zero), new EventHandler(mMode_Click));
				tsi.Visible = m.Selectable;
				if (m.Selectable)
					enabledCount = enabledCount + 1;
			}
			if (enabledCount < 2) mModeMenu.DropDown.Items.Clear();
			UpdateModeMenu();
		}


	    public override void Terminate()
        {
			IsInitialized = false;
			SavePersistency();
		}

		#endregion

		#region Persistency

		public override void SavePersistency()
		{
			IStatePersistenceService persistenceService = Services.Get<IStatePersistenceService>();
			if (persistenceService != null)
			{
				PersistencyDictionary dict = persistenceService.Load(this);
				persistenceService.Save(this, dict);
			}
		}

		public override void LoadPersistency()
		{
			IStatePersistenceService persistenceService = Services.Get<IStatePersistenceService>();
			if (persistenceService != null)
			{
				PersistencyDictionary dict = persistenceService.Load(this);
			}
		}

        #endregion

		#region Private helper methods

		private Dictionary<Mode, List<State>> GetAvailableStates()
		{
			Mode mode_agent = new Mode(1, "Agent", "Agent", true, Properties.Resources.mode_agent, "Not ready");
			Mode mode_other = new Mode(2, "Other", "Other", true, Properties.Resources.mode_other, "Not ready");

			State state_not_ready = new State(1, "Not ready", "Not Ready", true, Properties.Resources.state_not_ready);
			State state_ready = new State(2, "Ready", "Ready", true, Properties.Resources.state_ready);
			State state_busy = new State(3, "Busy", "Busy", false, Properties.Resources.state_busy);
			State state_be_right_back = new State(4, "Be right back", "Logged Out", true, Properties.Resources.state_offline);
			State state_unavailable = new State(5, "Unavailable", "unavailable", false, Properties.Resources.state_unavailable);
            State state_away = new State(5, "Away", "Logged Out", false, Properties.Resources.state_offline);

			Dictionary<Mode, List<State>> retVal = new Dictionary<Mode, List<State>>();
            retVal.Add(mode_agent, new List<State>(new State[] { state_not_ready, state_ready, state_busy, state_be_right_back, state_unavailable, state_away }));
			//retVal.Add(mode_other, new List<State>(new State[] { state_not_ready, state_ready, state_busy, state_be_right_back, state_unavailable }));

			return retVal;
		}

		#endregion

		#region Event handlers

        private void mAwayTimer_Tick(object sender, EventArgs e)
        {
            if (mLastPosition == Cursor.Position)
            {
                if (mBeforeState == null)
                    mBeforeState = StateManagementService.CurrentState;

                try
                {
					if (StateManagementService.CurrentState != StateManagementService.GetStateByName("Away"))
					{
						StateManagementService.SetState(this, StateManagementService.GetStateByName("Away"));
					}
                    mAwayTimer.Interval = 1000;
                }
                catch
                {
                    mAwayTimer.Stop();
                }
            }
            else
            {
                mLastPosition = Cursor.Position;
                if (mBeforeState != null)
                {
                    try
                    {
                        StateManagementService.SetState(this, mBeforeState);
                        mAwayTimer.Interval = mAutoAway * 1000;
                    }
                    catch
                    {
                        mAwayTimer.Stop();
                    }
                    mBeforeState = null;
                }
            }
        }

		private void smService_StateChanged(object sender, StateEventArgs e)
		{
			UpdateStateMenu();
		}

		private void smService_ModeChanged(object sender, ModeEventArgs e)
		{
			UpdateModeMenu();
		}

		private void mMode_Click(object sender, EventArgs e)
		{
			ToolStripDropDownItem mi = sender as ToolStripDropDownItem;
			if (mi != null)
			{
				foreach (Mode m in AvailableStates.Keys)
				{
					if (m.Name == mi.Text)
					{
						StateManagementService.SetMode(this, m);
						break;
					}
				}
				UpdateModeMenu();
			}
		}

		private void mState_Click(object sender, EventArgs e)
		{
			ToolStripDropDownItem mi = sender as ToolStripDropDownItem;
			if (mi != null)
			{
				foreach (State s in AvailableStates[StateManagementService.CurrentMode])
				{
					if (s.Name == mi.Text)
					{
						try
						{
							StateManagementService.SetState(this, s);
						}
						catch (Exception ex)
						{
							Host.LogManager.WriteInfo(this, string.Format("Cannot set state.\n{0}", ex.Message), "StateManagement");
						}
						break;
					}
				}
				UpdateStateMenu();
			}
		}

		private void StatusBar_Resize(object sender, EventArgs e)
		{
			if (sender == Host.StatusBar)
			{
				if (mSize != (Host.StatusBar as ToolStrip).Height - 9 )
				{
					mSize = (Host.StatusBar as ToolStrip).Height - 9;
					if (mSize < 8)
					{
						mSize = 8;
					}
					UpdateImages();
				}
			}
		}

		#endregion

    }
}
